package controllers

import play.api._
import play.api.mvc._
import play.api.libs.iteratee.{Iteratee, Enumerator}
import play.api.libs.ws.{WSResponseHeaders, WS}
import scala.concurrent.Future
import play.api.Play.current
import scala.concurrent.ExecutionContext.Implicits.global
import java.net.URL
import scala.util.Random
import java.util.Calendar
import scala.collection.mutable._
import java.io.{File, FileOutputStream}

object Application extends Controller {

  def index = Action.async {
    Future {
      Ok(views.html.index.render("Just Download"))
    }
  }

  def fileStatus = Action {

    Ok(s"${downloadingFile.id} - ${getSizeFriendly(downloadingFile.downloadedSize)} - ${downloadingFile.status}")
  }

  case class DownloadingFile(id: Long, downloadedSize: Long, status: String)
  var downloadingFile = DownloadingFile(0L, 0L, "ready")
  def justdownload(url: String) = Action.async {
    if(url != null || url.trim != ""){
      var isValidUrl = true
      try{
        new URL(url)
      } catch {
        case e: Exception =>
          isValidUrl = false
      }

      if(isValidUrl){
        WS.url(url).getStream().map{
          case (response, body) =>
            if(response.status == 200){
              val fid = System.currentTimeMillis()
              val outputStream = new FileOutputStream(s"/app/dist/download/$fid")
              downloadingFile = downloadingFile.copy(id = fid)

              val iteratee = Iteratee.foreach[Array[Byte]]{ bytes =>
                outputStream.write(bytes)
                println("write " + bytes.length)
                downloadingFile = downloadingFile.copy(downloadedSize = downloadingFile.downloadedSize + bytes.length)
              }

              (body |>>> iteratee).andThen{
                case result =>
                  outputStream.close()
                  result.get
              }.onComplete{ _ =>
                downloadingFile = downloadingFile.copy(status = "Complete")
              }

              Redirect(routes.Application.fileStatus)
            }else{
              BadGateway
            }
        }.recover{
          case e: Exception =>
            Ok(e.getMessage)
        }
      } else {
        Future {
          Ok("url is not valid.")
        }
      }
    } else {
      Future {
        Ok("url is empty.")
      }
    }
  }
  def justdownload1(url: String) = Action.async {
    if(url != null || url.trim != ""){
      var isValidUrl = true
      try{
        new URL(url)
      } catch {
        case e: Exception =>
          isValidUrl = false
      }

      if(isValidUrl){
        WS.url(url).getStream().map{
          case (response, body) =>
            if(response.status == 200){
              val contentType = response.headers.get("Content-Type").flatMap(_.headOption).getOrElse("application/octet-stream")
              response.headers.get("Content-Length") match {
                case Some(Seq(length)) =>
                  Ok.feed(body).as(contentType).withHeaders("Content-Length" -> length)
                case _ =>
                  Ok.chunked(body).as(contentType)
              }
            }else{
              BadGateway
            }
        }.recover{
          case e: Exception =>
            Ok(e.getMessage)
        }
      } else {
        Future {
          Ok("url is not valid.")
        }
      }
    } else {
      Future {
        Ok("url is empty.")
      }
    }
  }

  def getFileNameInUrl(url: String) = {
    val pos = url.lastIndexOf("/")
    val name = url.substring(pos + 1, url.length)
    if(name.trim == ""){
      "justdownload"
    } else {
      name
    }
  }

  def getSizeFriendly(size: Long): String = {
    size match {
      case size if size > 1000 * 1000 * 1000 =>
        "%.2fGB".format(size/1024.0/1024.0/1024.0)
      case size if size > 1000 * 1000 =>
        "%.2fMB".format(size/1024.0/1024.0)
      case size if size > 1000 =>
        "%.2fKB".format(size/1024.0)
      case size  =>
        s"${size}B"
    }
  }

}